#include "jtouch_p.h"
#include "qteguiglobal.h"
#include "touch/jeditoperationwidget.h"

#include <QTECore/jlog.h>
#include <QPlainTextEdit>
#include <QTextEdit>
#include <QLineEdit>
#include <QLabel>

#include <QGuiApplication>
#include <QInputMethodQueryEvent>
#include <QTouchEvent>
#include <QTimer>

namespace QTE
{

TouchFilter::TouchFilter()
{
	if( qgetenv("QT_QPA_PLATFORM") == "eglfs" )
		m_touch = true;
}

static void editOperat(QWidget *currInputWidget)
{
	if( J_OCT(QLabel*, currInputWidget) == nullptr )
		return ;

	auto flags = J_RCT(QLabel*, currInputWidget)->textInteractionFlags();

	if( (flags & Qt::TextSelectableByMouse) == 0 and (flags & Qt::TextSelectableByKeyboard) == 0 )
		jWarning() << "JEditOperationWidget: QLabel::textInteractionFlags set on the label need to include either Qt::TextSelectableByMouse or Qt::TextSelectableByKeyboard.";
	else
		(new JEditOperationWidget(currInputWidget))->show();
}

void TouchFilter::timerEvent(QTimerEvent *event)
{
	QObject::timerEvent(event);
	if( event->timerId() != m_timerID )
		return ;

	killTimer(m_timerID);
	m_timerID = -1;

	m_isPressed = false;
	emit pressMenu();

	editOperat(m_currInputWidget);
}

bool TouchFilter::eventFilter(QObject *watched, QEvent *event)
{
	auto widget = J_OCT(QWidget*, watched);
	if( widget == nullptr )
		return false;

	if( event->type() == QEvent::TouchBegin )
	{
		auto touchEvent = J_DCT(QTouchEvent*, event);
		if( touchEvent )
		{
			m_touch = true;

#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
			QCursor::setPos(widget->mapToGlobal(touchEvent->touchPoints()[0].pos().toPoint()));
#else
			QCursor::setPos(widget->mapToGlobal(touchEvent->points()[0].position().toPoint()));
#endif
		}
		return false;
	}

	else if( event->type() == QEvent::MouseMove )
	{
		if( m_isPressed and m_touch )
		{
			auto mouseEvent = J_DCT(QMouseEvent*, event);
			if( mouseEvent )
				QCursor::setPos(widget->mapToGlobal(mouseEvent->pos()));
		}
	}

	if( J_OCT(QLineEdit*, widget) == nullptr and
		J_DCT(QTextEdit*, widget->parentWidget()) == nullptr and
		J_DCT(QPlainTextEdit*, widget->parentWidget()) == nullptr and
		J_OCT(QLabel*, widget) == nullptr )
		return false;

	if( event->type() == QEvent::MouseButtonPress )
	{
		auto mouseEvent = J_DCT(QMouseEvent*, event);
		if( mouseEvent == nullptr or mouseEvent->button() != Qt::LeftButton or m_isPressed )
			return false;

		m_isPressed = true;
		if( m_touch )
			QCursor::setPos(widget->mapToGlobal(mouseEvent->pos()));

		if( m_lastObject == nullptr or widget != m_lastObject->parentWidget() )
		{
			if( m_currInputWidget and m_currInputWidget != widget )
			{
				if( J_DCT(QTextEdit*, widget->parentWidget()) or
					J_DCT(QPlainTextEdit*, widget->parentWidget()) )
				{
					if( m_currInputWidget != widget->parentWidget() )
					{
						m_currInputWidget->setProperty("QTE_TextInteraction", false);
						m_currInputWidget = nullptr;
					}
				}
				else
				{
					m_currInputWidget->setProperty("QTE_TextInteraction", false);
					m_currInputWidget = nullptr;
				}
			}
		}
		m_lastObject = widget;

		if( J_OCT(QLineEdit*, widget) )
			setInputWidget(widget);

		else if( J_DCT(QTextEdit*, widget->parentWidget()) or
				 J_DCT(QPlainTextEdit*, widget->parentWidget()) )
			setInputWidget(widget->parentWidget());

		else if( J_OCT(QLabel*, widget) )
		{
			auto label = J_RCT(QLabel*, widget);

			if( ((label->textInteractionFlags() & Qt::TextEditorInteraction) or
				 (label->textInteractionFlags() & Qt::TextBrowserInteraction)) )
				setInputWidget(widget);
		}
	}

	else if( event->type() == QEvent::MouseMove )
	{
		if( not m_isPressed )
			return false;

		if( m_timerID >= 0 )
		{
			killTimer(m_timerID);
			m_timerID = -1;
		}
	}

	else if( event->type() == QEvent::MouseButtonRelease )
	{
		if( not m_isPressed )
			return false;
		m_isPressed = false;

		if( m_timerID >= 0 )
		{
			killTimer(m_timerID);
			m_timerID = -1;
		}

		if( m_currInputWidget == nullptr )
			return false;

		auto var = m_currInputWidget->property("QTE_TextInteraction");
		if( not var.isValid() or var.toBool() == false )
			return false;

		QString text;

		if( J_OCT(QTextEdit*, m_currInputWidget) )
			text = J_RCT(QTextEdit*, m_currInputWidget)->textCursor().selectedText();

		else if( J_OCT(QPlainTextEdit*, m_currInputWidget) )
			text = J_RCT(QPlainTextEdit*, m_currInputWidget)->textCursor().selectedText();

		else if( J_OCT(QLineEdit*, m_currInputWidget) )
			text = J_RCT(QLineEdit*, m_currInputWidget)->selectedText();

		else if( J_OCT(QLabel*, m_currInputWidget) )
			text = J_RCT(QLabel*, m_currInputWidget)->selectedText();

		if( not text.isEmpty() )
		{
			QTimer::singleShot(50, m_currInputWidget, [this]()
			{
				emit pressMenu();
				editOperat(m_currInputWidget);
			});
		}
	}

	else if( event->type() == QEvent::InputMethodQuery )
	{
		auto imEvent = J_DCT(QInputMethodQueryEvent*, event);
		if( imEvent == nullptr )
			return false;

		auto var = widget->property("QTE_TextInteraction");
		if( var.isValid() and var.toBool() )
			imEvent->setValue(Qt::ImEnabled, false);
	}

	return false;
}

void TouchFilter::setInputWidget(QWidget *widget)
{
	m_timerID = startTimer(500);

	if( m_currInputWidget == widget )
		return ;

	else if( m_currInputWidget )
		m_currInputWidget->setProperty("QTE_TextInteraction", false);

	m_currInputWidget = widget;

	connect(m_currInputWidget, &QWidget::destroyed, this, [this]()
	{
		if( m_timerID >= 0 )
		{
			killTimer(m_timerID);
			m_timerID = -1;
		}
		m_currInputWidget = nullptr;
	});
}

void TouchFilter::cancelInputWidget()
{

}

/*-----------------------------------------------------------------------------------------------------------*/

namespace Gui
{

QTEGUI_EXPORT void setBasicTouchEnable(bool enable)
{
	auto &tf = TouchFilter::instance();

	if( enable )
		qApp->installEventFilter(&tf);
	else
		qApp->removeEventFilter(&tf);
}

} //namespace Gui

} //namespace QTE
